package com.example.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
import com.alibaba.csp.sentinel.util.TimeUtil;
import com.example.entity.CommonResult;
import com.example.entity.Dept;
import com.example.service.DeptFeignService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author: 21050134
 * @date: 2023/10/13 15:00
 * @description:
 */
@RestController
@Slf4j
public class DeptFeignController {
	@Resource
	private DeptFeignService deptFeignService;

	@RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
	@SentinelResource(value = "fallback",fallback = "handlerFallback")
	public CommonResult<Dept> get(@PathVariable("id") Integer id){
		initDegradeRule();
		monitor();
		log.info("------------主业务逻辑--------");
	    CommonResult<Dept> result = deptFeignService.get(id);
	    if(id == 6){
	    	log.info("------------主页逻辑，抛出非法参数异常");
	    	throw new IllegalArgumentException("IllegalArgumentException,抛出非法参数异常");
	    }else if(result.getData() == null ){
	    	log.info("------------主页逻辑，抛出空指针异常");
	    	throw new NullPointerException("NullPointerException，抛出空指针异常");
	    }
        return result;
	}

	@RequestMapping(value = "/dept/list",method = RequestMethod.GET)
	public CommonResult<List<Dept>> list(){
		return deptFeignService.list();
	}


	//处理异常的回退方法（服务降级）
	public CommonResult handlerFallback(Integer id,Throwable e){
		log.info("-----------服务降级-------");
		Dept dept = new Dept(id,"null1","null1");
		return new CommonResult(444,"",dept);
	}


	/**
	 * 自定义事件监听器，监听熔断器状态转换
	 */
	public void monitor(){
		EventObserverRegistry.getInstance().addStateChangeObserver("logging",
				(prevState, newState, rule, snapshotValue) -> {
					SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					if (newState == CircuitBreaker.State.OPEN) {
						// 变换至 OPEN state 时会携带触发时的值
						System.err.println(String.format("%s -> OPEN at %s, 发送请求次数=%.2f", prevState.name(),
								format.format(new Date(TimeUtil.currentTimeMillis())), snapshotValue));
					} else {
						System.err.println(String.format("%s -> %s at %s", prevState.name(), newState.name(),
								format.format(new Date(TimeUtil.currentTimeMillis()))));
					}
				});
	}

	/**
	 * 初始化熔断策略
	 */
    private static void initDegradeRule(){
    	List<DegradeRule> rules = Lists.newArrayList();
    	DegradeRule rule = new DegradeRule("fallback");
    	//熔断策略为异常比例
	    rule.setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType());
	    //异常比例阀值
	    rule.setCount(0.7);
	    //最小请求数
	    rule.setMinRequestAmount(100);
	    //统计时长 毫秒
	    rule.setStatIntervalMs(30000);
	    //熔断时长 秒
	    rule.setTimeWindow(10);
	    rules.add(rule);
	    DegradeRuleManager.loadRules(rules);
    }

}
